# -*- coding: utf-8 -*-

import yaml

from aeConn import dbHandle


class DBObject(object):
	""" 
	"""

	def __init__(self, obj=None):
		if obj:
			self._things = obj._things
			self.key = obj.key
			self._loaded = obj._loaded
			obj.forceUpdate()
			self._changed = set()
		else:
			self._things = {}
			self._changed = set()

			self.key = ''

			self._loaded = False


	def properties(self):
		return self._things


	def insert(self):
		params = {'type':self.getType()}
		body = self._dumpYAML()

		resp = dbHandle.postAction('insert', body, params)
		
		data = yaml.load(resp)
		self.key = data['key']
		
		self._loaded = True
		
	
	def forceUpdate(self):
		if self._changed:
			self._updateDB()
			
	
	def load(self):
		if not self.key:
			return
			
		params = {'type':self.getType(), 'key':self.key}
		
		resp = dbHandle.getAction('get', params)
		
		self._loadYAML(resp)
		
		self._loaded = True
			
	
	def search(self, obj=None):
		""" Searches the database using information in obj
			or if obj is None then uses information in self.
		"""
		
		if not obj:
			obj = self
			
		params = {'type':self.getType()}

		for key in obj._things.keys():
			if not obj._things[key]:
				del obj._things[key]
		body = obj._dumpYAML()

		resp = dbHandle.postAction('search', body, params)
		
		# Data is a list of keys
		data = yaml.load(resp)
		ret = [obj.__class__(key) for key in data]
		
		return ret


	def getType(self):
		return self.__class__.__name__


	def _loadYAML(self, yml):
		if type(yml) == str:
			data = yaml.load(yml)
		else:
			data = yml

		for key in data:
			if key in self._things:
				self._things[key] = data[key]


	def _dumpYAML(self, otherData = {}, properties=[]):
		""" Properties is an optional list of
			properties to dump.
		"""
		data = self.properties()
		if properties:
			keys = list(properties)
		else:
			keys = data.keys()
			
		for key in keys:
			if not key:
				continue #hack so that when properties is meant to be empty it works
			if isinstance(data[key], DBObject):
				data[key] = data[key].key

		for key in data.keys():
			if key not in keys:
				del data[key]

		data.update(otherData)
		
		#print "outputting: ", data
		
		return yaml.dump(data)


	def _updateDB(self):
		params = {'type':self.getType(), 'key':self.key}

		body = self._dumpYAML(properties=self._changed)

		dbHandle.postAction('update', body, params)


	def __getattr__(self, name):
		if name=='key':
			return self.key

		try:
			if self.key and not self._loaded:
				self.load()
			item = self._things[name]
		except KeyError:
			raise AttributeError, name

		return item

	def __setattr__(self, name, value):

		# "base case" to prevent recursion
		if name == '_things':
			self.__dict__[name] = value
			return

		if name in self._things:
			self._things[name] = value
			if self.key:
				self._changed.add(name)
		else:
			self.__dict__[name] = value		#if not in things then put in our dict
			
	def __del__(self):
		self.forceUpdate()

	def __eq__(self, other):
		if not isinstance(other, DBObject):
			return False
		if not self.key or not other.key:
			return False
		if self.key==other.key:
			return True
		else:
			return False

	def __ne__(self, other):
		return not (self.__eq__(other))
